package ru.sgu.acm.contester;

import ru.sgu.acm.dao.SubmitDao;
import ru.sgu.acm.dao.SubmitDaoImpl;
import ru.sgu.acm.misc.Constants;
import ru.sgu.acm.model.Submit;
import ru.sgu.acm.judge.Judge;
import static ru.sgu.acm.judge.misc.RetryingStrategy.startRetryingSection;
import org.apache.log4j.Logger;

import static java.lang.String.format;

/**
 * Pseudo contester application main class. It will be exactly one
 * instance of PseudoContester in application.
 * @author Vitaly Goldshteyn (VitalyGoldstein@gmail.com)
 */
public class PseudoContester {
    private SubmitDao submitDao;

    private static final Logger logger = Logger.getLogger(PseudoContester.class);

    private transient Status status = Status.CREATED;
    

    public void init() {
        status = Status.INITIALIZING;
        logger.info("PseudoContester " + Constants.getContesterId() + " initializing");

        submitDao = new SubmitDaoImpl();

        status = Status.INITIALIZED;
        logger.info("PseudoContester " + Constants.getContesterId() + " initialized");
    }

    public void run() {
        status = Status.RUNNING;
        logger.info("PseudoContester " + Constants.getContesterId() + " started main loop");
        while (status == Status.RUNNING) {
            // run testing
            Submit submit = submitDao.extractPending();
            if (submit != null) {
                logger.info(format("Testing submit id = %d.", submit.getId()));
                judge(submit);
            } else {
                logger.debug("No pending submits found.");
                try {
                    Thread.sleep(Constants.getPollPeriod());
                } catch (InterruptedException e) {
                    throw new IllegalStateException("Unable to sleep pseudo contester thread.", e);
                }
            }
        }
    }

    private void judge(Submit submit) {
        Judge judge = JudgeFactory.getInstance().getJudge(submit);

        startRetryingSection("judge");
        judge.judge(submit);
    }

    public void stop() {
        status = Status.STOPPING;
        logger.info("PseudoContester " + Constants.getContesterId() + " stopping");

        status = Status.STOPPED;
        logger.info("PseudoContester " + Constants.getContesterId() + " stopped");
    }

    public void pause() {
        stop();
    }

    private static enum Status {
        CREATED,
        INITIALIZING,
        INITIALIZED,
        RUNNING,
        PAUSING,
        PAUSED,
        STOPPING,
        STOPPED
    }
}
